"""
    Software : PyCharm
    File     : wbesocket.py
    Time     : 2021/5/23 9:11
    Author   : Pontoon
    describe :

    消息格式: {
        messageTypeId: 1    ->    系统通知消息
        messageTypeId: 2    ->    群聊消息
        messageTypeId: 3    ->    私聊消息
        messageTypeId: 4    ->    机器人消息

        user_state_id: 1  ->  在线
        user_state_id: 2  ->  离线

        from_uid: 发送者的uid
        nickname: 发送者的nickname
        avatar: 发送者的头像
        content: 消息的内容
        to_uid: 接收者的uid
    }

"""
import os
import json
from urllib.parse import parse_qs
from asgiref.sync import sync_to_async

import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chat_backend.settings")
django.setup()

from django.shortcuts import get_object_or_404
from projects.groups.models import Group


CONNECTION = {}


def get_uid_list_by_group_id(group_id):
    """
    获取代发消息的所有 uid
    :param group_id: 组的 id
    :param uid: 发送消息的 uid
    :return:
    """
    group = get_object_or_404(Group, pk=group_id)
    # 排除掉发送消息的uid

    user_list = group.member.all()
    if len(user_list) >= 1:
        uid_list = [str(user.uid) for user in user_list]
        print("uid_list: ", uid_list)
        return uid_list
    return None


async def send_group_msg(socket_list, system_msg):
    for send in socket_list():
        await send({'type': 'websocket.send', 'text': json.dumps(system_msg)})


async def get_connect_socket(uid_list="all"):
    """
    获取socket句柄
    :uid_list: 待发消息
    :return:
    """
    if uid_list == "all":
        return CONNECTION.values()
    socket_list = []
    for uid in uid_list:
        socket = CONNECTION.get(uid)
        if socket is not None:
            socket_list.append(socket)
    return socket_list


async def send_system_msg(socket_list, system_msg):
    """
    发送系统消息
        遍历 CONNECTION 的 values, 发送单条消息
    :param socket_list: socket 句柄
    :param system_msg: 待发消息
    :return:
    """
    print("socket_list: ", socket_list)
    print("system_msg: ", system_msg)
    for send in socket_list:
        await send({'type': 'websocket.send', 'text': json.dumps(system_msg)})


async def get_connect_uid():
    """
    获取 CONNECTION 的 keys
    :return:
    """
    system_msg = {"messageTypeId": 1}
    uid_list = list(CONNECTION.keys())
    system_msg['online_uids'] = uid_list
    return system_msg


async def get_uid(scope):
    """
    获取uid
    :param scope:
    :return:
    """
    query_string = scope.get('query_string', b'').decode()
    qs = parse_qs(query_string)
    uid = qs.get('uid', [''])[0]
    return uid


async def websocket_application(scope, receive, send):
    while True:
        event = await receive()
        print('event: ', event)
        # 收到建立 websocket 连接的请求
        if event['type'] == 'websocket.connect':
            """
            1) 建立socket连接
            2) 当有新用户连接的时候, 遍历所有socket连接句柄, 发送在线用户信息
            """
            print("-------------- 建立连接成功 --------------")
            await send({'type': 'websocket.accept'})

            # 得到 uid
            uid = await get_uid(scope)
            # 存储 websocket 的句柄
            CONNECTION[uid] = send
            # 将在线的 uid 推送给所有的客户端
            system_msg = await get_connect_uid()
            socket_list = await get_connect_socket()
            await send_system_msg(socket_list, system_msg)

        # 收到断开 websocket 连接的请求
        elif event['type'] == 'websocket.disconnect':
            """
            1) 弹出断开连接的socket句柄
            2) 遍历所有socket连接句柄, 发送在线用户信息
            """
            print("-------------- 断开连接成功 --------------")
            uid = await get_uid(scope)
            # 移除uid所对应的 socket 句柄
            CONNECTION.pop(uid)

            system_msg = await get_connect_uid()
            socket_list = await get_connect_socket()
            await send_system_msg(socket_list, system_msg)
            break

        # 收到 websocket 发送过来的数据
        elif event['type'] == 'websocket.receive':
            """
            消息的转发
                注意: 转发是要拿到接收消息一方的socket句柄
            """
            receive_text = event.get('text', None)
            if receive_text:
                receive_data_dict = json.loads(receive_text)
                msg_type = receive_data_dict.get("messageTypeId")
                if msg_type == 2:
                    # 转发群消息
                    """
                    {
                        messageTypeId: 2,
                        group_id: xxxx,
                        uid: xxxxx,
                        content: xxxxx,
                    }
                    """
                    # 1) 通过 group_id 查找到所有的uid
                    group_id = receive_data_dict.get("groupId")
                    uid_list = await sync_to_async(get_uid_list_by_group_id, thread_sensitive=True)(group_id)
                    # 2) 发送消息
                    socket_list = await get_connect_socket(uid_list)
                    print("socket_list: ", socket_list)
                    if len(socket_list) > 0:
                        await send_system_msg(socket_list, receive_data_dict)
                    continue
                elif msg_type == 3:
                    # 转发私人消息
                    to_uid = receive_data_dict.get("to_uid")
                    send = CONNECTION.get(to_uid)
                    await send({
                        'type': 'websocket.send',
                        'text': json.dumps(receive_data_dict)
                    })

                else:
                    break
        else:
            # 其他情况, 正常的 websocket 通讯连接
            break
